class Wsocket {
	url = ''
	timeout = 30000
	cb = null
	socketStatus = 0 //避免重复连接 0 无连接 1-9连接中 10 已连接
	heartbeatTimeOut = null //检测服务器端是否还活着
	reconnectTimeOut = null //重连之后多久再次重连
	reconnectNum = 0 //重连次数
	socketTask = null //ws对象
	msgQueue = []
	netIsConnected = false
	netType = 'none'
	autoFlag = true

   events = {
     onOpen:  null,
     onClose: null,
     onError: null,
   }
	/**
	 * 构造方法
	 * @param {String} _url
	 * @param {number} _timeout
	 * @param {Function} _cb
	 */
	constructor(_url, _cb, _timeout = 50000) {
		this.url = _url //地址
		this.timeout = _timeout //心跳检测
		this.cb = _cb
	}
	
	connect(){
		// 监听网络状态变化
		uni.onNetworkStatusChange((res) => {
			console.log('WebSocket NetStatus', res.isConnected);
			console.log('WebSocket NetStatus', res.networkType);
			this.netIsConnected = res.isConnected
			this.netType = res.networkType
			this.reconnectNum = 0
			if (this.autoFlag) this.reconnect()
		});
		
		try {
			uni.getNetworkType({
				success: (res) => {
					console.log('WebSocket getNetworkType', res.networkType);
					this.netType = res.networkType
					this.netIsConnected = true
		
					this.reconnect();
				}
			});
		
			// 有return ，则构造方法返回return的对象，没有，则返回new的对象
			// return this.hhh
		} catch (e) {
			console.log('连接初始化失败', e);
		}
		
	}

	/**
	 * 连接创建方法，维护连接状态、心跳、回调
	 */
	connectSocketInit() {

		if (!this.netIsConnected || this.netType == 'none') return
		if (this.socketStatus > 0) return
		if (!this.url) return

		this.heartbeatTimeOut && clearTimeout(this.heartbeatTimeOut)

		this.socketStatus = 1;

		console.log('正准备建立websocket...', this.url);

		uni.onSocketError((res)=> {
			this.socketStatus = 0;
			console.log('WebSocket 连接错误！', this.socketStatus, res);
		});

		uni.onSocketClose((res)=> {
			this.socketStatus = 0;
			console.log('WebSocket 连接关闭！', res);
		});

		uni.onSocketOpen((res)=> {
			if(this.events.onOpen){
				this.events.onOpen(res)
			}
			this.socketStatus = 10;
			console.log('WebSocket 连接打开！', res);
		});

		// 建立连接
		this.socketTask = uni.connectSocket({
			url: this.url,
			success: (data) => {
				this.socketStatus = 2;
				console.log("websocket 建立中...");
			},
			fail: (data) => {
				this.socketStatus = 0;
				console.log("websocket 建立失败...");
			},
			complete: (data) => {
				this.socketStatus = 3;
				console.log("websocket 建立完成...");
			}
		});

		// 连接打开
		// 上面的构造方法必须存在，否则 this.socketTask.onOpen 不可用
		this.socketTask.onOpen((res) => {
			console.log("socketTask 正常了");
			// 连接标识
			this.socketStatus = 10;
			this.reconnectNum = 0;
			// 心跳
			this.ping();
			// 注：只有连接正常打开中 ，才能正常收到消息
			this.socketTask.onMessage((res) => {
				// console.log(res.data.type,res.data)
				this.receive(res.data)
			});
		})

		// 连接关闭
		// 这里仅是事件监听【如果socket关闭了会执行】
		this.socketTask.onClose(() => {
			console.log("socketTask 关闭了")
			this.socketStatus = 0;
		})

		// 连接错误
		// 监听连接失败，这里代码我注释掉的原因是因为如果服务器关闭后，和下面的onclose方法一起发起重连操作，这样会导致重复连接
		this.socketTask.onError(() => {
			console.log("socketTask 错误了")
			this.socketStatus = 0;
		})

	}

	/**
	 * 重新连接，循环检查连接状态
	 */
	reconnect() {

		// 失败重连频率
		const reconnect_time = [3000, 3000, 3000, 3000, 10000, 10000, 10000, 20000, 20000, 50000]
		// 自身巡检频率
		let reconnect_timeout = 30000

		// 任何情况下，清理定时器
		this.reconnectTimeOut && clearTimeout(this.reconnectTimeOut)

		if (this.socketStatus < 10) {
			// 失败重连
			if (this.reconnectNum > 50) return
			if (this.reconnectNum < reconnect_time.length) {
				reconnect_timeout = reconnect_time[this.reconnectNum]
			} else {
				reconnect_timeout = reconnect_time[reconnect_time.length - 1]
			}

			//console.log("Wsocket 重新连接",this.socketStatus,this.reconnectNum,reconnect_timeout)

			this.reconnectNum = this.reconnectNum + 1

			this.reconnectTimeOut = setTimeout(() => {
				// 连接创建
				this.connectSocketInit();
				this.reconnect()
			}, reconnect_timeout)

			return;
		}

		//console.log("Wsocket 自身巡检",this.socketStatus,this.reconnectNum,reconnect_timeout)

		// 自身巡检循环
		this.reconnectTimeOut = setTimeout(() => {
			// 连接创建
			this.connectSocketInit();
			this.reconnect()
		}, reconnect_timeout)

	}

	/**
	 * 重新打开链接
	 */
	restart() {

		if (this.socketStatus >= 10) {
			console.log("连接已打开");
			return;
		}

		this.autoFlag = true

		this.reconnect()

	}

	/**
	 * 关闭链接
	 */
	close() {

		if (this.socketStatus < 10) {
			console.log("连接未打开");
			return;
		}

		this.heartbeatTimeOut && clearTimeout(this.heartbeatTimeOut)
		this.reconnectTimeOut && clearTimeout(this.reconnectTimeOut)

		this.autoFlag = false

		this.socketTask.close()

	}

	/**
	 * 发送消息
	 * @param {String} value
	 */
	send(value) {

		value = JSON.stringify(value)

		this.msgQueue.push(value);

		if (this.socketStatus < 10) {
			console.log("**********", "连接错误，消息发送失败", value);
			return;
		}
		// console.log("this.msgQueue ",this.this.msgQueue.length);
		let msg = '';
		while (msg = this.msgQueue.shift()) {
			// 注：只有连接正常打开中 ，才能正常成功发送消息
			this.socketTask.send({
				data: msg,
				async success() {
					// console.log("消息发送成功");
				},
			});
		}

	}

	/**
	 * 接收消息
	 * @param {String} value
	 */
	receive(data) {

		data = JSON.parse(data)
		if (typeof this.cb !== 'function') {
			console.log('receive callback fun is not function', data.type, data)
			return
		}
		this.cb(data)

	}

	getStatus() {
		return this.socketStatus
	}

	/**
	 * 开启心跳检测
	 */
	ping() {

		this.heartbeatTimeOut && clearTimeout(this.heartbeatTimeOut)

		if (this.socketStatus >= 10) {
			let data = {
				'event': 'ping'
			}
			this.send(data);
		}

		if (this.timeout < 10000) return

		// 定时器
		this.heartbeatTimeOut = setTimeout(() => {
			this.ping()
		}, this.timeout)

	}

}

export default Wsocket